package com.cy.lib.exception;

import android.content.Context;
import android.os.Environment;
import android.support.v7.app.AlertDialog;
import android.util.Log;
import android.view.WindowManager;

import com.cy.lib.util.PackageUtils;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.PrintStream;
import java.lang.Thread.UncaughtExceptionHandler;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;

/**
 * @author CY
 * @title Crash
 * @date 2014-12-4
 */
public class CrashHandler extends Exception implements UncaughtExceptionHandler, Runnable {


    /*
    android.permission.READ_PHONE_STATE
    CrashHandler.instance().init(this);
    */

    private static final long serialVersionUID = 6259636331411969255L;

    private static CrashHandler mCrashHandler;
    StringBuffer mSbInfo = new StringBuffer();
    String mDate;
    Context mContext;
    File mLogFile;
    OnCrashHandlerListener mHandlerListener;

    private CrashHandler() {
    }

    public static synchronized CrashHandler instance() {
        if (mCrashHandler == null) {
            mCrashHandler = new CrashHandler();
        }
        return mCrashHandler;
    }

    public void init(Context context) {
        init(context, null);
    }

    public void init(Context context, File logFile) {
        init(context, logFile, null);
    }

    public void init(Context context, File logFile, OnCrashHandlerListener listener) {
        mContext = context;
        mLogFile = logFile;
        mHandlerListener = listener;
        Thread.setDefaultUncaughtExceptionHandler(this);
    }

    @Override
    public void uncaughtException(Thread thread, Throwable ex) {
        ex.printStackTrace();
        mDate = new SimpleDateFormat("yyyy-MM-dd#HH-mm-ss", Locale.CHINA).format(new Date(System.currentTimeMillis()));
        String deviceInfo = PackageUtils.getDeviceInfoStr(mContext);
        try {
            mSbInfo.append("deviceInfo:" + deviceInfo + "\n");
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            ex.printStackTrace(new PrintStream(baos, true));
            mSbInfo.append(new String(baos.toByteArray()));
            baos.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
        String log = mSbInfo.toString();
        Log.e("uncaughtException:", log + "");

        if (mHandlerListener != null) {
            mHandlerListener.uncaughtException(thread, ex, log);
        }
        showCrashDialog();
        new Thread(this).start();
    }

    @Override
    public void run() {
        handleException();
        if (mHandlerListener == null) {
            android.os.Process.killProcess(android.os.Process.myPid());
        }
    }


    public void handleException() {

        boolean isMounted = Environment.getExternalStorageState().equals(android.os.Environment.MEDIA_MOUNTED);
        if (isMounted) {

            try {

                if (mLogFile == null) {
                    String label = (String) mContext.getPackageManager().getApplicationLabel(mContext.getApplicationInfo());
                    File dir = new File(Environment.getExternalStorageDirectory(), label);
                    mLogFile = new File(dir, "crash-" + mDate + ".log");
                }

                mLogFile.getParentFile().mkdirs();
                mLogFile.createNewFile();

                FileOutputStream fos = new FileOutputStream(mLogFile);
                fos.write(mSbInfo.toString().getBytes());
                fos.flush();
                fos.close();
            } catch (FileNotFoundException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }

    }


    private void showCrashDialog() {
        AlertDialog.Builder builder = new AlertDialog.Builder(mContext);
        AlertDialog dialog = builder.setTitle("程序异常报告").setMessage(mSbInfo.toString()).create();
        dialog.getWindow().addFlags(WindowManager.LayoutParams.TYPE_SYSTEM_ERROR);
        dialog.show();
    }

    public interface OnCrashHandlerListener {
        void uncaughtException(Thread thread, Throwable ex, String log);
    }
}
